package com.polaris.live.manager

import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.polaris.live.CustomUncaughtExceptionHandler
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.mvvm.fragment.BaseVmFragment
import com.polaris.live.common.mvvm.fragment.FragmentLifecycleEventObserver
import com.polaris.live.common.network.getSuccessResult
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.StructUtils
import com.polaris.live.common.util.resettableLazy
import com.polaris.live.common.util.resettableManager
import com.polaris.live.im.sfs.bean.pusher.PusherNoticeMessage
import com.polaris.live.im.sfs.bean.pusher.UserStateMessage
import com.polaris.live.net.stateService
import com.polaris.live.net.userService
import com.polaris.live.resp.go_resp.StateUserObserveBean
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap
import kotlin.time.Duration.Companion.seconds

/**
 * 用户状态管理器
 *
 * @author Created by lucas on 2023/10/18 11:45
 */
object UserStateManager {

    private val handler = CoroutineExceptionHandler { _, e ->
        LogExt.logE(CustomUncaughtExceptionHandler.TAG, "UserStateManager", e)

        FirebaseCrashlytics.getInstance().recordException(e)
    }

    private val resettableManager = resettableManager()
    private val userStateScope by resettableLazy(resettableManager) {
        CoroutineScope(CoroutineScopeManager.defaultDispatcher + SupervisorJob() + handler)
    }

    private val userStateWrappers = ConcurrentHashMap<LifecycleOwner, UserStateWrapper>()
    private val userStateListeners = StructUtils.newSaleSet<UserStateListener>()

    /**
     * 登出时调用，重置所有的监听和协程
     */
    fun reset() {
        userStateListeners.clear()
        val scope = userStateScope
        resettableManager.reset()
        scope.cancel()
    }

    /**
     * 添加用户状态监听
     *
     * 会自动取消
     *
     * @param owner 生命周期
     * @param observerListener 监听用户ids
     * @param changeListener 用户状态变化
     * @param resumeState 是否在恢复时重新获取数据，如果为true在Activity的[Lifecycle.Event.ON_RESUME]和Fragment的[FragmentLifecycleEventObserver.onHiddenChanged]为true时会重新获取状态数据
     */
    fun observe(
        owner: LifecycleOwner,
        observerListener: UserObserveListener,
        changeListener: UserStateListener,
        resumeState: Boolean = true,
    ) {
        if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            return
        }

        val wrapper = UserStateWrapper(
            owner,
            observerListener,
            changeListener,
            resumeState,
            null
        )
        userStateWrappers[owner] = wrapper

        if (owner.lifecycle.currentState == Lifecycle.State.RESUMED && owner.isShowed()) {
            wrapper.startObserve()
        }

        owner.lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                when (event) {
                    Lifecycle.Event.ON_RESUME -> {
                        if (owner.isShowed()) {
                            if (owner is BaseVmFragment<*>) {
                                wrapper.fragmentStartObserve(owner)
                            } else {
                                wrapper.startObserve()
                            }
                        }
                    }

                    Lifecycle.Event.ON_PAUSE -> {
                        wrapper.stopObserve()
                    }

                    Lifecycle.Event.ON_DESTROY -> {
                        wrapper.stopObserve()

                        userStateWrappers.remove(owner)
                    }

                    else -> {
                        //ignore
                    }
                }
            }
        })
        if (owner is BaseVmFragment<*>) {
            owner.addFragmentLifecycleEventObserver { hidden ->
                if (hidden) {
                    wrapper.stopObserve()
                } else {
                    if (owner.lifecycle.currentState == Lifecycle.State.RESUMED) {
                        wrapper.fragmentStartObserve(owner)
                    }
                }
            }
        }
    }

    private fun UserStateWrapper.fragmentStartObserve(owner: BaseVmFragment<*>) {
        if (owner.isCreated()) {
            startObserve()
        } else {
            //这里极少数情况下会出现
            owner.withLoaded {
                startObserve()
            }
        }
    }

    private fun LifecycleOwner.isShowed(): Boolean {
        return if (this is Fragment) {
            !isHidden
        } else {
            true
        }
    }

    /**
     * 主动更新监听状态的用户
     *
     * 比如列表在滚动时，可以主动触发当前可见的用户状态变化
     */
    fun updateUserObserve(owner: LifecycleOwner, userIds: List<Long>) {
        val ids = userIds.distinct()

        userStateWrappers[owner]?.apply {
            updateObserveJob?.cancel()
            updateObserveJob = userStateScope.launch {
                try {
                    if (ids.isEmpty()) {
                        return@launch
                    }
                    //判断与上次是否一致，如果一致认为已经同步了状态，可以少一次请求
                    if (observeUserIds?.containsAll(ids) != true) {
                        resumeUserState(ids)

                        //主动获取用户信息后通知更变监听用户
                        if (owner.lifecycle.currentState == Lifecycle.State.RESUMED) {
                            observeUserIds = ids
                            stateService.observeUserState(StateUserObserveBean(ids))
                        }
                    } else {
                        //否则需要判断距离上次的时间
                        val lastResumeTime = lastResumeTime
                        if (lastResumeTime == null || CacheUtil.getServerTime() - lastResumeTime > 5000) {
                            resumeUserState(ids)
                        }
                    }
                } finally {
                    if (updateObserveJob == coroutineContext[Job]) {
                        updateObserveJob = null
                    }
                }
            }
        }
    }

    private fun UserStateWrapper.startObserve() {
        observerJob?.cancel()
        observerJob = userStateScope.launch {
            try {
                invokeObserve()
            } finally {
                if (observerJob == coroutineContext[Job]) {
                    observerJob = null
                }
            }
        }
        refreshJob?.cancel()
        refreshJob = userStateScope.launch {
            try {
                invokeRefresh()
            } finally {
                if (refreshJob == coroutineContext[Job]) {
                    refreshJob = null
                }
            }
        }
        userStateListeners.add(changeListener)

        if (resumeState) {
            resumeUserState()
        }

        LogExt.logI("UserManagerDispatcher") {
            val remainNames = userStateListeners.map { it::class.simpleName }.joinToString { "," }
            "observe start: ${owner::class.simpleName}, names = $remainNames"
        }
    }

    private suspend fun UserStateWrapper.invokeObserve() = coroutineScope {
        while (isActive) {
            val userIds = getObserveUserIds().distinct()

            observeUserIds = userIds

            if (userIds.isNotEmpty()) {
                try {
                    stateService.observeUserState(StateUserObserveBean(userIds))
                } catch (_: Throwable) {
                }
            }

            delay(25.seconds)
        }
    }

    private suspend fun UserStateWrapper.invokeRefresh() = coroutineScope {
        while (isActive) {
            delay(15.seconds)

            resumeUserState(observeUserIds ?: emptyList())
        }
    }

    private fun UserStateWrapper.stopObserve() {
        userStateListeners.remove(changeListener)
        observerJob?.cancel()

        //这里只有有任务的时候才打印，因为有可能已经取消过了
        if (observerJob != null) {
            LogExt.logI("UserManagerDispatcher") {
                val remainNames =
                    userStateListeners.map { it::class.simpleName }.joinToString { "," }
                "observe stop: ${owner::class.simpleName}, names = $remainNames"
            }
        }

        observerJob = null
        refreshJob?.cancel()
        refreshJob = null
    }

    private fun UserStateWrapper.resumeUserState() {
        userStateScope.launch {
            val userIds = getObserveUserIds()
            resumeUserState(userIds)
        }
    }

    private suspend fun UserStateWrapper.resumeUserState(userIds: List<Long>) {
        if (userIds.isEmpty()) {
            return
        }

        lastResumeTime = CacheUtil.getServerTime()

        val userStates = getUserStates(userIds)
        if (userStates.isNotEmpty()) {
            withContext(CoroutineScopeManager.mainDispatcher) {
                changeListener.onUserStateChange(userStates)
            }
        }
    }

    private suspend fun UserStateWrapper.getObserveUserIds(): List<Long> =
        withContext(CoroutineScopeManager.mainDispatcher) {
            observerListener.onObserveUserIds()
        }

    private suspend fun getUserStates(userIds: List<Long>): List<UserStateMessage> {
        try {
            val ids = userIds.distinct()
            val resp = userService.infoState(ids.joinToString { it.toString() })
            val timestamp = resp.timestamp
            val result = resp.getSuccessResult()
            if (result != null) {
                return result.map {
                    UserStateMessage(it, timestamp)
                }
            }
        } catch (_: Throwable) {
        }

        return emptyList()
    }

    internal suspend fun eventDispatch(receipt: PusherNoticeMessage) {
        val message = JsonUtils.fromJson<UserStateMessage>(receipt.content)
        if (message == null) {
            return
        }

        withContext(CoroutineScopeManager.mainDispatcher) {
            userStateListeners.forEach {
                it.onUserStateChange(listOf(message))
            }
        }
    }
}

class UserStateWrapper(
    /**
     * 所有者
     */
    val owner: LifecycleOwner,
    /**
     * 获取需要监听的用户ids
     */
    val observerListener: UserObserveListener,
    /**
     * 用户状态变化
     */
    val changeListener: UserStateListener,
    /**
     * 是否在恢复时重新获取数据
     */
    val resumeState: Boolean,
    /**
     * 上一次恢复的时间
     */
    @field:Volatile
    var lastResumeTime: Long? = null,
    /**
     * 当前监控的用户id
     */
    @field: Volatile
    var observeUserIds: List<Long>? = null,
    /**
     * 监听协程
     */
    @field:Volatile
    var observerJob: Job? = null,
    /**
     * 刷新协程，用于防止消息丢失
     */
    @field:Volatile
    var refreshJob: Job? = null,
    /**
     * 更新监听协程
     */
    @field:Volatile
    var updateObserveJob: Job? = null,
)

fun interface UserObserveListener {

    /**
     * 获取需要监听的用户ids
     */
    fun onObserveUserIds(): List<Long>

}

fun interface UserStateListener {

    /**
     * 用户状态变化
     */
    fun onUserStateChange(states: List<UserStateMessage>)

}